package com.live555.decoder;

import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Build;
import android.view.SurfaceHolder;

import java.nio.ByteBuffer;

/**
 * 功能描述：h264解码类
 *
 * @author：ZC 创建时间：2018/6/26 10:56
 * 最后修改日期：
 */
public class H264Decoder {
    private MediaCodec mCodec;
//    private long mBaseTick = 0;
//    private long mNowTick = 0;

    private static int HEAD_OFFSET = 512;
    private MediaCodec.BufferInfo mBufferInfo;
    private ByteBuffer[] mInputBuffers;
    private boolean flag = false;
    private ByteBuffer mInputBuffer;
    //    private int timeInternal = 0;
//    private boolean f = true;
    private int frameRate = 30;
    private int bitRate = 2500000;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public H264Decoder(SurfaceHolder holder, String mimeType, int w, int h, int timeInternal) {
        try {
//            mCodec =
//                    MediaCodec.createByCodecName("OMX.allwinner.video.decoder.avc");
            mCodec = MediaCodec.createDecoderByType(mimeType);
//            mBaseTick = System.currentTimeMillis();
//            this.timeInternal = timeInternal;
            MediaFormat mediaFormat = MediaFormat.createVideoFormat(mimeType, w, h);
//            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
//            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
//            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
//            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, timeInternal); //关键帧间隔时间 单位s

//            mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(sps));
//            mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(pps));
            mCodec.configure(mediaFormat, holder.getSurface(), null, 0);
            mCodec.start();

            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public boolean onFrame(byte[] buf, int offset, int length) {
        try {
            if (mCodec != null && flag) {
//                LogUtils.d("Media", "onFrame start");
//                Get input buffer index
                mInputBuffers = mCodec.getInputBuffers();
                int inputBufferIndex = mCodec.dequeueInputBuffer(100000);

//                if (mCount == 0) {
//                    mBaseTick = System.currentTimeMillis();
//                }
                if (inputBufferIndex >= 0 && flag && mCodec != null) {
                    mInputBuffer = mInputBuffers[inputBufferIndex];
                    mInputBuffer.clear();
                    mInputBuffer.put(buf, offset, length);
                    mCodec.queueInputBuffer(inputBufferIndex, 0, length, 0, 0);
//                    mCount++;
                } else {
//                    LogUtils.d("Media", "onFrame index:" + inputBufferIndex);
                    return false;
                }
//                Get output buffer index
                mBufferInfo = new MediaCodec.BufferInfo();
                int outputBufferIndex = mCodec.dequeueOutputBuffer(mBufferInfo, 0);
                while (outputBufferIndex >= 0 && flag && mCodec != null) {
                    mCodec.releaseOutputBuffer(outputBufferIndex, true);
                    outputBufferIndex = mCodec.dequeueOutputBuffer(mBufferInfo, 0);
                }
            }
        } catch (Exception e) {
//            e.printStackTrace();
        }
        /*
         * do { mNowTick = System.currentTimeMillis();
		 * 
		 * if ((mNowTick - mBaseTick) < (mCount*(1000/this.timeInternal))) { try
		 * { Thread.sleep(10); } catch (InterruptedException e) { // TODO
		 * Auto-generated catch block e.printStackTrace(); }
		 * 
		 * } else break; }while(true);
		 */
//        LogUtils.e("Media", "onFrame end");

//		 LogUtils.d("Media", "one frame take time:"+ (mNowTick - mBaseTick));

        return true;
    }

    /**
     * @param buffer
     * @param len
     * @return 找到h264帧头，帧头偏移，返回0则找不到
     */
    public int findHead(byte[] buffer, int len) {
        int i;
        for (i = HEAD_OFFSET; i < len; i++) {
            if (checkHead(buffer, i)) {
                break;
            }
        }
        if (i == len) {
            return 0;
        }
        if (i == HEAD_OFFSET) {
            return 0;
        }
        return i;
    }

    /**
     * @param buffer
     * @param offset
     * @return 校验缓冲区是否为h264头
     */
    public boolean checkHead(byte[] buffer, int offset) {
        // 00 00 00 01
        if (buffer[offset] == 0 && buffer[offset + 1] == 0 && buffer[offset + 2] == 0 && buffer[3] == 1) {
            return true;
        }
        // 00 00 01
        if (buffer[offset] == 0 && buffer[offset + 1] == 0 && buffer[offset + 2] == 1) {
            return true;
        }
        return false;
    }

    /**
     * 关闭和重置解码器
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void DecoderClose() {
        flag = false;
        if (mCodec != null) {
            try {
                mCodec.stop();
            }catch (IllegalStateException i){
            }
            mCodec.release();
            mCodec = null;
        }
    }
}
